package main

import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"
)

type Server struct {
	Ip   string
	Port int

	// 在线用户列表
	OnlineMap map[string]*User
	mapLock sync.RWMutex

	// 消息广播的channel
	Message chan string
}

// 创建一个serve的接口
func AddServer(ip string, port int) *Server {
	server := &Server{
		Ip:   ip,
		Port: port,
		OnlineMap: make(map[string]*User),
		Message: make(chan string),
	}
	return server
}

// 监听 Message广播消息的channel的goroutine，
// 一旦有消息就发送给全部的在线USer
func (server *Server) ListenMessager(){
	for {
		msg:= <- server.Message
		server.mapLock.Lock()
		for _,cli := range server.OnlineMap{
			cli.C <-msg
		}
		server.mapLock.Unlock()
	}
}


// 广播消息
func (server *Server) BroadCast(user *User,msg string){
	sendMsg:=fmt.Sprintf("【%v】%v:%v",user.Addr,user.Name,msg)
	server.Message <- sendMsg
	fmt.Println(sendMsg)
}

func (server *Server) Handler(conn net.Conn) {
// 稍微有点Bug，改进的话可以改成定时器
	var x =0
 var user = NewUser(conn,server)
	//用户上线
	user.Online()

	//监听用户是否活跃的channel
	isLive:= make(chan bool) 

	// 接收客户端传递的消息
	go func ()  {
		buf:=make([]byte,4096)
		for {
			n,err:=conn.Read(buf)
			if n==0{
 //这样的写法会造成服务端出现大量CLOSE_WAIT，return也只是退出当前协程，而不是Handle
              user.Offline()
			  x=1
			  return
			}
			if err!= nil && err!= io.EOF{
				fmt.Println("conn read err",err)
				return
			}
			// 提取用户的消息，去除"\n"
			msg:= string(buf[:n-1])
			// 将得到的消息进行处理，私聊的私聊，广播的广播
			// 改名的改名
			user.DoMessage(msg)

			// 用户的任意消息，代表用户活跃
			isLive <- true
		}
	}()
	if x==1{
		return
	}
	// 当前handler阻塞
	for {
		select {
//这里select 第二个case定时器触发后，处于阻塞状态。当满足第一个 case 的条件后，
//打破了 select 的阻塞状态，每个条件又开始判断，第2个 case 的判断条件一执行，就重置定时器了。
			// select执行完一个case就结束，
			// 否则阻塞（定时器倒计时）
		case<- isLive:
			//当前用户是活跃的，应该重置定时器
			// 不做任何事情，为了激活select,
			// 更新下面的定时器
		case <-time.After(time.Second*300):
			// 已经超时
			// 将当前user强制关闭
			user.SendMsg("用户不活跃，已被自动踢出")
			//销毁使用的资源
			close(user.C)
			return
		}
	}
}
func (server *Server) Start() {

	//socket listen
	ip := fmt.Sprintf("%s:%d", server.Ip, server.Port)
	
	listener, err := net.Listen("tcp", ip)
	if err != nil {
		fmt.Println("listen err:", err.Error())
		return
	}
	//close listen socket
	defer listener.Close()
	// 启动监听message的goroutine
	go server.ListenMessager()

	for {
		//accept
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listen accept err:", err.Error())
			return
		}
		//do handler
		go server.Handler(conn)
	}

}

